#include "UdpReceiver.h"
#include <boost/asio.hpp>
#include <boost/asio/ip/udp.hpp>
#include <iostream>
#include <array>

// 构造函数，初始化 socket 并绑定端口
UdpReceiver::UdpReceiver(const std::string &bindIP, const std::string &remoteIP, unsigned short port)
    : recv_buffer_(2048) // 设置缓冲区大小
{
    _bindIP = bindIP == "Any" ? "" : bindIP;
    // _bindIP = bindIP;
    _remoteIP = remoteIP;
    _port = port;
}

UdpReceiver::~UdpReceiver()
{
}

// 启动异步接收数据
bool UdpReceiver::start()
{
    // io_context 是 Boost.Asio 的事件处理器
    io_context_ = std::make_unique<boost::asio::io_context>();

    // try
    // {
    //     if (!_remoteIP.empty())
    //     {
    //         // 组播
    //         boost::asio::ip::udp::endpoint listen_endpoint;
    //         if (!_bindIP.empty())
    //         {
    //             listen_endpoint = boost::asio::ip::udp::endpoint(boost::asio::ip::address::from_string(_bindIP), _port);
    //         }
    //         else
    //         {
    //             listen_endpoint = boost::asio::ip::udp::endpoint(boost::asio::ip::udp::v4(), _port);
    //         }

    //         // 打开 socket，并绑定到端点
    //         socket_ = std::make_unique<boost::asio::ip::udp::socket>(*io_context_);
    //         // 打开 socket，并绑定到端点
    //         socket_->open(listen_endpoint.protocol());
    //         socket_->set_option(boost::asio::ip::udp::socket::reuse_address(true));                                        // 允许地址重用
    //         socket_->bind(listen_endpoint);                                                                                // 绑定到指定端点
    //         socket_->set_option(boost::asio::ip::multicast::join_group(boost::asio::ip::address::from_string(_remoteIP))); // 加入组播组
    //     }
    //     else
    //     {
    //         // 广播/单播
    //         // 创建 UDP 端点，绑定到本地 IP 和端口
    //         boost::asio::ip::udp::endpoint local_endpoint;
    //         if (!_bindIP.empty())
    //         {
    //             local_endpoint = boost::asio::ip::udp::endpoint(boost::asio::ip::address::from_string(_bindIP), _port);
    //         }
    //         else
    //         {
    //             local_endpoint = boost::asio::ip::udp::endpoint(boost::asio::ip::udp::v4(), _port);
    //         }
    //         socket_ = std::make_unique<boost::asio::ip::udp::socket>(*io_context_, local_endpoint);
    //     }
    // }
    try
    {
        if (!_remoteIP.empty())
        {
            // 组播
            boost::asio::ip::udp::endpoint listen_endpoint;
            if (!_bindIP.empty())
            {
                listen_endpoint = boost::asio::ip::udp::endpoint(
                    boost::asio::ip::make_address(_bindIP),
                    _port);
            }
            else
            {
                listen_endpoint = boost::asio::ip::udp::endpoint(
                    boost::asio::ip::udp::v4(),
                    _port);
            }

            // 打开 socket，并绑定到端点
            socket_ = std::make_unique<boost::asio::ip::udp::socket>(*io_context_);
            socket_->open(listen_endpoint.protocol());
            socket_->set_option(boost::asio::ip::udp::socket::reuse_address(true));
            socket_->bind(listen_endpoint);
            socket_->set_option(boost::asio::ip::multicast::join_group(
                boost::asio::ip::make_address(_remoteIP)));
        }
        else
        {
            // 广播/单播
            boost::asio::ip::udp::endpoint local_endpoint;
            if (!_bindIP.empty())
            {
                local_endpoint = boost::asio::ip::udp::endpoint(
                    boost::asio::ip::make_address(_bindIP),
                    _port);
            }
            else
            {
                local_endpoint = boost::asio::ip::udp::endpoint(
                    boost::asio::ip::udp::v4(),
                    _port);
            }
            socket_ = std::make_unique<boost::asio::ip::udp::socket>(*io_context_, local_endpoint);
        }
    }
    catch (const std::exception &e)
    {
        raiseError("Exception occurred while connecting to " + _remoteIP + ":" + std::to_string(_port) + (_bindIP.empty() ? "" : ("(interface:" + _bindIP + ")")));
        return false;
    }

    _isWorking = true;
    startReceive();

    // 检查 socket_ 是否成功打开
    if (!socket_->is_open())
    {
        raiseError("Socket is not open!");
        return false;
    }
    else
    {
        // 启动事件循环
        // io_context.run() 会进入事件循环，不断监听和处理异步任务（例如数据接收、定时器、连接等）
        // 调用，否则异步操作不会生效
        // io_context_->run();  //没有事件时，它会阻塞等待。
        // 将 io_context 放到单独线程运行
        io_thread_ = std::make_unique<std::thread>([this]()
                                                   { io_context_->run(); });
    }
    return true;
}

void UdpReceiver::startReceive()
{
    // 继续监听下一次数据
    socket_->async_receive_from(
        boost::asio::buffer(recv_buffer_), remote_endpoint_,
        [this](const boost::system::error_code &error, std::size_t bytes_transferred)
        {
            handleReceive(error, bytes_transferred);
        });
}

// 数据接收处理
void UdpReceiver::handleReceive(const boost::system::error_code &error, std::size_t bytes_transferred)
{
    if (!error)
    {
        if (!_isWorking)
        {
            return;
        }

        bool isReStartReceive = false;
        try
        {
            // 截取有效数据
            std::vector<uint8_t> data(recv_buffer_.begin(), recv_buffer_.begin() + bytes_transferred);

            // 调用用户自定义回调函数
            if (callback_)
            {
                // callback_(data);
                std::async(std::launch::async, [this, data]()
                           { callback_(data); });
            }
            if (_isWorking)
            {
                isReStartReceive = true;
                startReceive();
            }
        }
        catch (const boost::system::system_error &e)
        {
            raiseError(std::string(e.what()));
        }
        catch (const std::exception &e)
        {
            raiseError(std::string(e.what()));
        }

        if (!isReStartReceive && _isWorking)
        {
            try
            {
                startReceive();
            }
            catch (const std::exception &e)
            {
                raiseError(std::string(e.what()));
            }
        }
    }
    else
    {
        raiseError("Receive error: " + error.message());
    }
}

bool UdpReceiver::setCallback(DatagramReceived callback)
{
    callback_ = callback;
    return true;
}

void UdpReceiver::raiseError(const std::string &message)
{
    std::cout << message << std::endl;
}

bool UdpReceiver::stop()
{
    if (!_isWorking)
        return true;

    _isWorking = false;

    if (socket_)
    {
        boost::system::error_code ec;
        socket_->close(ec);
        socket_.reset();
    }

    if (io_context_)
    {
        io_context_->stop();
        if (io_thread_ && io_thread_->joinable())
        {
            io_thread_->join();
        }
        io_context_.reset();
    }

    return true;
}

bool UdpReceiver::dispose()
{
    return stop();
}